package com.fragrance.service.impl;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.iot.client.IotClient;
import com.aliyuncs.AcsResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.RpcAcsRequest;
import com.aliyuncs.iot.model.v20170420.ApplyDeviceWithNamesRequest;
import com.aliyuncs.iot.model.v20170420.ApplyDeviceWithNamesResponse;
import com.aliyuncs.iot.model.v20170420.BatchGetDeviceStateRequest;
import com.aliyuncs.iot.model.v20170420.BatchGetDeviceStateResponse;
import com.aliyuncs.iot.model.v20170420.BatchGetDeviceStateResponse.DeviceStatus;
import com.aliyuncs.iot.model.v20170420.CreateProductRequest;
import com.aliyuncs.iot.model.v20170420.CreateProductResponse;
import com.aliyuncs.iot.model.v20170420.CreateProductResponse.ProductInfo;
import com.aliyuncs.iot.model.v20170420.DeleteDevicePropRequest;
import com.aliyuncs.iot.model.v20170420.DeleteDevicePropResponse;
import com.aliyuncs.iot.model.v20170420.GetDeviceShadowRequest;
import com.aliyuncs.iot.model.v20170420.GetDeviceShadowResponse;
import com.aliyuncs.iot.model.v20170420.PubBroadcastRequest;
import com.aliyuncs.iot.model.v20170420.PubBroadcastResponse;
import com.aliyuncs.iot.model.v20170420.PubRequest;
import com.aliyuncs.iot.model.v20170420.PubResponse;
import com.aliyuncs.iot.model.v20170420.QueryApplyStatusRequest;
import com.aliyuncs.iot.model.v20170420.QueryApplyStatusResponse;
import com.aliyuncs.iot.model.v20170420.QueryDeviceByNameRequest;
import com.aliyuncs.iot.model.v20170420.QueryDeviceByNameResponse;
import com.aliyuncs.iot.model.v20170420.QueryDeviceByNameResponse.DeviceInfo;
import com.aliyuncs.iot.model.v20170420.QueryDevicePropRequest;
import com.aliyuncs.iot.model.v20170420.QueryDevicePropResponse;
import com.aliyuncs.iot.model.v20170420.QueryDeviceRequest;
import com.aliyuncs.iot.model.v20170420.QueryDeviceResponse;
import com.aliyuncs.iot.model.v20170420.QueryPageByApplyIdRequest;
import com.aliyuncs.iot.model.v20170420.QueryPageByApplyIdResponse;
import com.aliyuncs.iot.model.v20170420.QueryPageByApplyIdResponse.ApplyDeviceInfo;
import com.aliyuncs.iot.model.v20170420.RRpcRequest;
import com.aliyuncs.iot.model.v20170420.RRpcResponse;
import com.aliyuncs.iot.model.v20170420.RegistDeviceRequest;
import com.aliyuncs.iot.model.v20170420.RegistDeviceResponse;
import com.aliyuncs.iot.model.v20170420.SaveDevicePropRequest;
import com.aliyuncs.iot.model.v20170420.SaveDevicePropResponse;
import com.aliyuncs.iot.model.v20170420.UpdateDeviceShadowRequest;
import com.aliyuncs.iot.model.v20170420.UpdateDeviceShadowResponse;
import com.aliyuncs.iot.model.v20170420.UpdateProductRequest;
import com.aliyuncs.iot.model.v20170420.UpdateProductResponse;
import com.fragrance.service.IotApiService;

public class IotApiServiceImpl implements IotApiService {

	private final static Logger logger = LoggerFactory.getLogger(IotApiServiceImpl.class);

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private AcsResponse execute(RpcAcsRequest request) {
		AcsResponse response = null;
		try {
			DefaultAcsClient client = IotClient.getClient();
			response = client.getAcsResponse(request);
		} catch (Exception e) {
			logger.error("iot调用发生异常", e);
		}
		return response;
	}

	/**
	 * 创建产品
	 *
	 * @param productName
	 *            产品名称
	 * @param productDesc
	 *            产品描述 可空
	 * @return 产品的PK
	 */
	public ProductInfo createProduct(String productName, String productDesc) {
		try {
			CreateProductRequest request = new CreateProductRequest();
			request.setName(productName);
			request.setDesc(productDesc);
			CreateProductResponse response = (CreateProductResponse) execute(request);
			if (response != null && response.getSuccess()) {
				logger.info("创建产品成功productKey:" + response.getProductInfo().getProductKey());
				return response.getProductInfo();
			} else {
				logger.error("创建产品失败requestId:" + response.getRequestId() + "，原因:" + response.getErrorMessage());
			}
		} catch (Exception e) {
			logger.info("发生异常", e);
		}
		return null;
	}

	/**
	 * 修改产品
	 *
	 * @param productKey
	 *            产品PK 必需
	 * @param productName
	 *            产品名称 非必需
	 * @param productDesc
	 *            产品描述 非必需
	 */
	public Boolean updateProduct(String productKey, String productName, String productDesc) {
		try {
			UpdateProductRequest request = new UpdateProductRequest();
			request.setProductKey(productKey);
			request.setProductName(productName);
			request.setProductDesc(productDesc);
			UpdateProductResponse response = (UpdateProductResponse) execute(request);
			if (response != null && response.getSuccess()) {
				logger.info("修改产品成功！");
				return true;
			} else {
				logger.error("修改产品失败requestId:" + response.getRequestId() + "，原因:" + response.getErrorMessage());
			}
		} catch (Exception e) {
			logger.error("修改产品失败", e);
		}
		return false;
	}

	/**
	 * 注册设备
	 *
	 * @param productKey
	 *            产品pk
	 * @param deviceName
	 *            设备名称 非必须
	 * @return 设备名称
	 */
	public RegistDeviceResponse registDevice(String productKey, String deviceName) {
		try {
			RegistDeviceRequest request = new RegistDeviceRequest();
			request.setProductKey(productKey);
			request.setDeviceName(deviceName);
			RegistDeviceResponse response = (RegistDeviceResponse) execute(request);
			if (response != null && response.getSuccess()) {
				logger.info("创建设备成功！deviceName:" + response.getDeviceName() + ",deviceSecret:"
						+ response.getDeviceSecret());
				return response;
			} else {
				logger.error("创建设备失败requestId:" + response.getRequestId() + "，原因：" + response.getErrorMessage());
			}
		} catch (Exception e) {
			logger.error("注册设备", e);
		}
		return null;
	}

	/**
	 * 查询设备列表
	 *
	 * @param productKey
	 *            产品PK
	 * @param pageSize
	 *            每页显示条数 非必须
	 * @param currentPage
	 *            当前页 非必须
	 */
	public QueryDeviceResponse queryDevice(String productKey, Integer pageSize, Integer currentPage) {
		try {
			QueryDeviceRequest request = new QueryDeviceRequest();
			request.setProductKey(productKey);
			request.setPageSize(pageSize);
			request.setCurrentPage(currentPage);
			QueryDeviceResponse response = (QueryDeviceResponse) execute(request);
			if (response != null && response.getSuccess()) {
				logger.info("查询设备成功" + JSONObject.toJSONString(response));
				return response;
			} else {
				logger.error("查询设备失败requestId:" + response.getRequestId() + ",原因：" + response.getErrorMessage());
			}
		} catch (Exception e) {
			logger.error("查询设备列表失敗", e);
		}
		return null;
	}

	/**
	 * 根据设备名称查询设备信息
	 */
	public DeviceInfo queryDeviceByName(String productKey, String deviceName) {
		try {
			QueryDeviceByNameRequest request = new QueryDeviceByNameRequest();
			request.setProductKey(productKey);
			request.setDeviceName(deviceName);
			QueryDeviceByNameResponse response = (QueryDeviceByNameResponse) execute(request);
			if (response != null && response.getSuccess()) {
				logger.info("查询设备成功！ " + JSONObject.toJSONString(response));
				return response.getDeviceInfo();
			} else {
				logger.error("查询设备失败requestId:" + response.getRequestId() + "原因：" + response.getErrorMessage());
			}
		} catch (Exception e) {
			logger.error("根据设备名称查询设备信息失敗", e);
		}
		return null;
	}

	/**
	 * 批量查询设备状态
	 *
	 * @param productKey
	 *            产品pk
	 * @param deviceNames
	 *            设备名称集合
	 */
	public List<DeviceStatus> batchGetDeviceStatus(String productKey, List<String> deviceNames) {
		try {
			BatchGetDeviceStateRequest request = new BatchGetDeviceStateRequest();
			request.setProductKey(productKey);
			request.setDeviceNames(deviceNames);
			BatchGetDeviceStateResponse response = (BatchGetDeviceStateResponse) execute(request);
			if (response != null && response.getSuccess()) {
				logger.info("查询设备成功！ " + JSONObject.toJSONString(response));
				response.getDeviceStatusList();
			} else {
				logger.error("查询设备失败requestId:" + response.getRequestId() + ",原因：" + response.getErrorMessage());
			}
		} catch (Exception e) {
			logger.error("批量查询设备状态失敗", e);
		}
		return null;
	}

	/**
	 * 批量申请设备
	 *
	 * @param productKey
	 *            产品pk
	 * @return 申请单id
	 */
	public Long applyDeviceWithNames(String productKey, List<String> deviceNames) {
		try {
			ApplyDeviceWithNamesRequest request = new ApplyDeviceWithNamesRequest();
			request.setProductKey(productKey);
			request.setDeviceNames(deviceNames);
			ApplyDeviceWithNamesResponse response = (ApplyDeviceWithNamesResponse) execute(request);
			if (response != null && response.getSuccess()) {
				logger.info("批量申请设备成功！ applyId: " + response.getApplyId());
				return response.getApplyId();
			} else {
				logger.error("批量申请设备失败requestId:" + response.getRequestId() + ",原因：" + response.getErrorMessage());
			}
		} catch (Exception e) {
			logger.error("批量申请设备", e);
		}
		return null;
	}

	/**
	 * 查询申请单是否执行完毕
	 *
	 * @param applyId
	 *            申请单id
	 * @return 是否执行完毕
	 */
	public Boolean queryApplyStatus(Long applyId) {
		try {
			QueryApplyStatusRequest request = new QueryApplyStatusRequest();
			request.setApplyId(applyId);
			QueryApplyStatusResponse response = (QueryApplyStatusResponse) execute(request);
			if (response != null && response.getSuccess()) {
				logger.info("查询申请单执行状态成功！ 是否执行完成: " + response.getFinish());
				return response.getFinish();
			} else {
				logger.error("查询申请单执行状态失败！requestId:" + response.getRequestId() + "，原因：" + response.getErrorMessage());
			}
		} catch (Exception e) {
			logger.error("查询申请单是否执行完毕", e);
		}
		return false;
	}

	/**
	 * 分页查询批量申请的设备
	 *
	 * @param applyId
	 *            申请单id
	 * @param pageSize
	 *            每页显示条数
	 * @param currentPage
	 *            当前页
	 */
	public List<ApplyDeviceInfo> queryPageByApplyId(Long applyId, Integer pageSize, Integer currentPage) {
		try {
			QueryPageByApplyIdRequest request = new QueryPageByApplyIdRequest();
			request.setApplyId(applyId);
			request.setPageSize(pageSize);
			request.setCurrentPage(currentPage);
			QueryPageByApplyIdResponse response = (QueryPageByApplyIdResponse) execute(request);
			if (response != null && response.getSuccess()) {
				logger.info("分页查询批量申请的设备成功！ " + JSONObject.toJSONString(response));
				return response.getApplyDeviceList();
			} else {
				logger.error("分页查询批量申请的设备失败requestId:" + response.getRequestId() + "，原因：" + response.getErrorMessage());
			}
		} catch (Exception e) {
			logger.error("分页查询批量申请的设备", e);
		}
		return null;
	}

	/**
	 * https://help.aliyun.com/document_detail/30581.html?spm=a2c4g.11186623.2.4.TnfWVC
	 * 
	 * pub消息
	 *
	 * @param productKey
	 *            pk
	 * @param topic
	 *            topic
	 * @param msg
	 *            消息内容
	 */
	public String publishMssage(String productKey, String topic, String msg) {
		try {
			PubRequest request = new PubRequest();
			request.setProductKey(productKey);
			request.setTopicFullName(topic);
			request.setMessageContent(Base64.encodeBase64String(msg.getBytes()));
			request.setQos(1);
			PubResponse response = (PubResponse) execute(request);
			if (response != null && response.getSuccess()) {
				logger.info("发送消息成功！messageId：" + response.getMessageId());
				return response.getMessageId();
			} else {
				logger.error("发送消息失败requestId:" + response.getRequestId() + "原因：" + response.getErrorMessage());
			}
		} catch (Exception e) {
			logger.error("发送消息失败", e);
		}
		return null;
	}

	/**
	 * 发送广播消息
	 *
	 * @param productKey
	 *            产品pk
	 * @param topic
	 *            广播topic /broadcast/${pk}/+
	 * @param msg
	 *            消息内容
	 */
	public Boolean publishBroadcast(String productKey, String topic, String msg) {
		try {
			PubBroadcastRequest request = new PubBroadcastRequest();
			request.setProductKey(productKey);
			request.setTopicFullName(topic);
			request.setMessageContent(Base64.encodeBase64String(msg.getBytes()));
			PubBroadcastResponse response = (PubBroadcastResponse) execute(request);
			if (response != null && response.getSuccess()) {
				logger.info("发送消息成功！");
				return true;
			} else {
				logger.error("发送消息失败！requestId:" + response.getRequestId() + "原因：" + response.getErrorMessage());
			}
		} catch (Exception e) {
			logger.error("发送广播消息失败", e);
		}
		return false;
	}

	/**
	 * https://help.aliyun.com/document_detail/69797.html?spm=a2c4g.11186623.6.685.zjlOsv
	 * 
	 * 发消息给设备并同步返回响应 发送rrpc消息
	 *
	 * @param productKey
	 *            产品pk
	 * @param deviceName
	 *            设备名称
	 * @param msg
	 *            消息内容
	 */
	public Boolean sendRrpcMsg(String productKey, String deviceName, String msg) {
		try {
			RRpcRequest request = new RRpcRequest();
			request.setProductKey(productKey);
			request.setDeviceName(deviceName);
			request.setRequestBase64Byte(Base64.encodeBase64String(msg.getBytes()));
			request.setTimeout(5000);
			RRpcResponse response = (RRpcResponse) execute(request);
			if (response != null && response.getSuccess()) {
				logger.info("rrpc消息发送成功！messageId:" + response.getMessageId() + ", payloadBase64Byte："
						+ new String(Base64.decodeBase64(response.getPayloadBase64Byte())));
				return true;
			} else {
				logger.error("rrpc消息发送失败requestId:" + response.getRequestId() + "原因：" + response.getErrorMessage());
			}
		} catch (Exception e) {
			logger.error("发送rrpc消息失败", e);
		}
		return false;
	}

	/**
	 * 获取设备影子信息
	 *
	 * @param productKey
	 *            产品pk
	 * @param deviceName
	 *            设备名称
	 * @return 影子信息
	 */
	public JSONObject  getDeviceShadow(String productKey, String deviceName) {
		try {
			GetDeviceShadowRequest request = new GetDeviceShadowRequest();
			request.setProductKey(productKey);
			request.setDeviceName(deviceName);
			GetDeviceShadowResponse response = (GetDeviceShadowResponse) execute(request);
			if (response != null && response.getSuccess()) {
				logger.info("获取设备影子成功！shadowMessage:" + response.getShadowMessage());
				// 如果影子内容不为空，获取版本信息
				if (StringUtils.isNotEmpty(response.getShadowMessage())) {
					JSONObject shadowObject = JSONObject.parseObject(response.getShadowMessage());
					long shadowVersion = shadowObject.getLong("version");
				}
				logger.info("获取设备影子信息: " + response.getShadowMessage());
				return JSONObject.parseObject(response.getShadowMessage());
			} else {
				logger.error("获取设备影子失败requestId:" + response.getRequestId() + ",原因：" + response.getErrorMessage());
			}
		} catch (Exception e) {
			logger.error("获取设备影子信息", e);
		}
		return null;
	}

	/**
	 * 更新影子信息
	 *
	 * @param productKey
	 *            产品pk
	 * @param deviceName
	 *            设备名称
	 * @param shadowVersion
	 * 
	 * @param attributeMap
	 * 
	 */
	public Boolean updateDeviceShadow(String productKey, String deviceName, Long shadowVersion,
			LinkedHashMap<String, Object> attributeMap) {
		try {
			UpdateDeviceShadowRequest request = new UpdateDeviceShadowRequest();
			request.setProductKey(productKey);
			request.setDeviceName(deviceName);
			Set<String> attSet = attributeMap.keySet();
			Map attMap = new LinkedHashMap();
			for (String attKey : attSet) {
				attMap.put(attKey, attributeMap.get(attKey));
			}
			Map reportedMap = new LinkedHashMap();
			reportedMap.put("desired", attMap);
			Map shadowJsonMap = new LinkedHashMap();
			shadowJsonMap.put("method", "update");
			shadowJsonMap.put("state", reportedMap);
			shadowJsonMap.put("version", shadowVersion);
			String shadow = JSON.toJSONString(shadowJsonMap);
			request.setShadowMessage(shadow);
			UpdateDeviceShadowResponse response = (UpdateDeviceShadowResponse) execute(request);
			if (response != null && response.getSuccess()) {
				logger.info("更新设备影子成功！");
				return true;
			} else {
				logger.error("更新设备影子失败requestId:" + response.getRequestId() + ",原因：" + response.getErrorMessage());

			}
		} catch (Exception e) {
			logger.error("更新影子信息", e);
		}
		return false;
	}

	/**
	 * 保存设备属性
	 */
	public Boolean saveDeviceProp(String productKey, String deviceName, Map<String, Object> props) {
		try {
			SaveDevicePropRequest request = new SaveDevicePropRequest();
			request.setProductKey(productKey);
			request.setDeviceName(deviceName);
			request.setProps(JSON.toJSONString(props));
			SaveDevicePropResponse response = (SaveDevicePropResponse) execute(request);
			if (response != null && response.getSuccess()) {
				logger.info("保存设备属性成功！");
				return true;
			} else {
				logger.error("保存设备属性失败requestId:" + response.getRequestId() + ",原因：" + response.getErrorMessage());
			}
		} catch (Exception e) {
			logger.error("保存设备属性", e);
		}
		return false;
	}

	/**
	 * 删除设备属性
	 */
	public Boolean deleteDeviceProp(String productKey, String deviceName) {
		try {
			DeleteDevicePropRequest request = new DeleteDevicePropRequest();
			request.setProductKey(productKey);
			request.setDeviceName(deviceName);
			request.setPropKey("temperature");
			DeleteDevicePropResponse response = (DeleteDevicePropResponse) execute(request);
			if (response != null && response.getSuccess()) {
				logger.info("删除设备属性成功！");
				return true;
			} else {
				logger.error("删除设备属性失败requestId:" + response.getRequestId() + ",原因：" + response.getErrorMessage());
			}
		} catch (Exception e) {
			logger.error("保存设备属性", e);
		}
		return false;
	}

	/**
	 * 查询设备属性
	 */
	public Boolean queryDeviceProp(String productKey, String deviceName) {
		try {
			QueryDevicePropRequest request = new QueryDevicePropRequest();
			request.setProductKey(productKey);
			request.setDeviceName(deviceName);
			QueryDevicePropResponse response = (QueryDevicePropResponse) execute(request);
			if (response != null && response.getSuccess()) {
				logger.info("查询设备属性成功！属性信息：" + response.getProps());
				return true;
			} else {
				logger.error("查询设备属性失败！requestId:" + response.getRequestId() + "原因：" + response.getErrorMessage());
			}
		} catch (Exception e) {
			logger.error("查询设备属性", e);
		}
		return false;
	}
	
	public static void main(String[] args) {
		IotApiService service = new IotApiServiceImpl();
		String productName = "xfjProduct";
//		ProductInfo  productInfo= service.createProduct(productName, "香氛机");
		//{"createUserId":1789958389878730,"fromSource":"iothub","productDesc":"香氛机","productKey":"a1M01Sn0KXj","productName":"xfjProduct"}
//		System.out.println(JSON.toJSONString(productInfo));
		
		productName = "xfjProduct_1";
	//	Boolean flag = service.updateProduct("a1M01Sn0KXj", productName, "香氛机1号");
		//System.out.println(flag);
		//RegistDeviceResponse devResp = service.registDevice("a1M01Sn0KXj", "xfjDev1");
		//System.out.println(JSON.toJSONString(devResp));
		
		DeviceInfo deviceInfo =  service.queryDeviceByName("a1NcRC0sKf8", "dev_1");
		System.out.println(JSON.toJSONString(deviceInfo));
		System.out.println("001023411102130011021300110213007101012".length());
		service.publishMssage("a1NcRC0sKf8", "/a1NcRC0sKf8/dev_1/get", "world001023411102130011021300110213007101012");
//		service.sendRrpcMsg("a1NcRC0sKf8", "dev_1", "world001023411102130011021300110213007101012");
	}
}
